package com.atguigu.srb.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.common.result.ResponseEnum;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @Description:
 * @Author: Gavin
 * @Date: 7/12/2023 7:02 PM
 */
@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.首先从请求中获取请求的路径(我们是根据路径里面是否包含auth来决定是否鉴权)
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        //2.如果路径不需要进行鉴权的话,直接放行
        AntPathMatcher matcher = new AntPathMatcher();
        boolean match = matcher.match("/api/**/auth/**", path);
        if(!match){
            //放行请求
            return chain.filter(exchange);
        }
        //3.如果路径需要进行鉴权
        //3.1获取请求头中的token
        String token = request.getHeaders().getFirst("token");
        //3.2使用JwtUtils判断token是否有效
        if (JwtUtils.checkToken(token)) {
            //进来这里面,说明鉴权结果是ok的,可以直接放行
            return chain.filter(exchange);
        }
        //4.走到这里说明鉴权失败,需要给客户端一个需要登录的响应
        //token鉴权失败可能的原因 : token过期,或者被篡改,或者为空,需要拒绝请求
        //4.1手动生成相应报文,讲一个需要登录的R对象的json字符串设置到响应报文的响应体中
        //R code = -211 , message = "未登录" , data = null
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", ResponseEnum.LOGIN_AUTH_ERROR.getCode());
        jsonObject.put("message",ResponseEnum.LOGIN_AUTH_ERROR.getMessage());
        String s = jsonObject.toJSONString();
        //4.2防止响应乱码,配置一个响应报文头的编码格式
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
        //4.3将上面生成的json字符串设置到响应报文的响应体中
        //将上面的json字符串转为数据缓存对象,通过Mono转为publisher对象后,写入到response中
        DataBuffer wrap = response.bufferFactory().wrap(s.getBytes());
        return response.writeWith(Mono.just(wrap));
    }

    //这个方法是用来对filter进行排序的,值越小优先级越高
    @Override
    public int getOrder() {
        return 0;
    }
}
